package AC.Controller;

import java.util.LinkedList;
import java.util.List;

import ioio.lib.api.AnalogInput;
import ioio.lib.api.DigitalInput;
import ioio.lib.api.DigitalInput.Spec.Mode;
import ioio.lib.api.DigitalOutput;
import ioio.lib.api.PwmOutput;
import ioio.lib.api.exception.ConnectionLostException;
import ioio.lib.util.AbstractIOIOActivity;
import ClimateControlProcessor.ClimateObjects.Constant;
import ClimateControlProcessor.ClimateObjects.Constant.FANDIRECTION;
import ClimateControlProcessor.ClimateObjects.Constant.MODE;
import ClimateControlProcessor.ClimateObjects.UserDesiredSettings;
import ClimateControlProcessor.Process;
import android.accounts.Account;
import android.accounts.AccountManager;
import android.app.admin.DevicePolicyManager;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.graphics.Color;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.SeekBar;
import android.widget.TextView;
import android.widget.ToggleButton;

public class ACCActivity extends  AbstractIOIOActivity  {	
	// Get context of application
	private static Context context;
	protected static final int REQUEST_ENABLE = 0;
    DevicePolicyManager devicePolicyManager;
    ComponentName adminComponent;

	
	/** Declare button Objects for fan directions */
	private Button FDbutton1;
	private Button FDbutton2;
	private Button FDbutton3;
	private Button FDbutton4;
	private Button FDbutton5;
	private Button AutoButton;
	private Button ManualButton;
	private Button DebugButton; 
	private ToggleButton ACButton;
	private ToggleButton SystemButton;
	private ToggleButton FDbutton6;
	private TextView mTextTemp;
	private NumberPicker numPick; 
	private ImageView fan; 
	private TextView plus; 
	private TextView minus;
	private TextView debugView; 

	private Drawable originDraw; 
	private SeekBar seekFanSpeed;
	
	//reading input of devices for debug only
	private float headStatus;
	private float footStatus;
	private float defrostStatus;
	private float recircStatus;
	private float compclStatus;
	private float monoValveVolt;
	private float fanspeedVolt;
	
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main); 
        
        AutoButton = (Button) findViewById(R.id.Auto);
		ManualButton = (Button) findViewById(R.id.Manual);
		DebugButton = (Button) findViewById(R.id.Debug);
		ACButton = (ToggleButton) findViewById(R.id.Ac);
		SystemButton= (ToggleButton) findViewById(R.id.Off);
        FDbutton1 = (Button) findViewById(R.id.Fd1);
        FDbutton2 = (Button) findViewById(R.id.Fd2);
        FDbutton3 = (Button) findViewById(R.id.Fd3);
        FDbutton4 = (Button) findViewById(R.id.Fd4);
        FDbutton5 = (Button) findViewById(R.id.Fd5);
        FDbutton6 = (ToggleButton) findViewById(R.id.Fd6); 
        FDbutton6.setChecked(true);   
        seekFanSpeed = (SeekBar)findViewById(R.id.FanSeekBar);
        numPick= (NumberPicker)findViewById(R.id.numberPicker);
        fan= (ImageView) findViewById(R.id.Fan);
        plus= (TextView) findViewById(R.id.Plus);
        minus= (TextView) findViewById(R.id.Minus1);
        debugView= (TextView) findViewById(R.id.debugView);
        
        originDraw = FDbutton1.getBackground();    
        registerEvents();
     
        mTextTemp = (TextView) findViewById(R.id.Temp);     
        
        // get context to read profile in assets folder
        ACCActivity.context = getApplicationContext();
        ACButton.setChecked(true);
        SystemButton.setChecked(true);
        
        // set desired temperature
		Constant.desiredConfig = new UserDesiredSettings();	
		Constant.desiredConfig.setDesiredTemp(numPick.mCurrent);
    }
    
    /*
     * Register events for layout controls
     */
    private void registerEvents(){
    	final FanDirection eventHandler = new FanDirection();
    	FDbutton1.setOnClickListener(new OnClickListener() {			
			public void onClick(View v) {
				setActive(Constant.VALUE1);
				eventHandler.OnClickButton1(v);
			}
		});
        
        FDbutton2.setOnClickListener(new OnClickListener() {			
			public void onClick(View v) {
				setActive(Constant.VALUE2);
				eventHandler.OnClickButton2(v);				
			}
		});
        FDbutton3.setOnClickListener(new OnClickListener() {			
			public void onClick(View v) {
				setActive(Constant.VALUE3);
				eventHandler.OnClickButton3(v);			
			}
		});
        FDbutton4.setOnClickListener(new OnClickListener() {			
			public void onClick(View v) {
				setActive(Constant.VALUE4);
				eventHandler.OnClickButton4(v);				
			}
		});
        FDbutton5.setOnClickListener(new OnClickListener() {			
			public void onClick(View v) {
				setActive(Constant.VALUE5);
				eventHandler.OnClickButton5(v);				
			}
		});
        FDbutton6.setOnClickListener(new OnClickListener() {			
			public void onClick(View v) {
				eventHandler.OnClickButton6(v);
				
			}
		});
                
        AutoButton.setOnClickListener(new OnClickListener() {			
			public void onClick(View v) {	
				flipView(View.VISIBLE, View.INVISIBLE);
				Process.onClickAuto(v); 
				setConfig();			
			}
		});
        ManualButton.setOnClickListener(new OnClickListener() {			
			public void onClick(View v) {
				flipView(View.VISIBLE, View.INVISIBLE);
				Process.onClickManual(v); 
				setConfig(); 
			}
		});
        DebugButton.setOnClickListener(new OnClickListener() {			
			public void onClick(View v) {
				Process.onClickDebug(v); 
				setConfig(); 		
				seekFanSpeed.setProgress(Constant.currentACConfig.currBlowMotor.getSeekBarValue());
				flipView(View.INVISIBLE, View.VISIBLE);
				try {
					Thread.sleep(500);
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
				
				String debugViewContent = "";				
				//if(Constant.head ){
				if(headStatus>0.9){
					debugViewContent = debugViewContent + Constant.DEBUG_AIR_DIR_HEAD;
				}
				else 
					debugViewContent = debugViewContent + Constant.DEBUG_AIR_DIR_HEAD_ERROR;
				
				if(footStatus>0.9){
					debugViewContent = debugViewContent + Constant.DEBUG_AIR_DIR_FOOT;
				}	
				else 
					debugViewContent = debugViewContent + Constant.DEBUG_AIR_DIR_FOOT_ERROR;
				
				if(defrostStatus>0.9){
					debugViewContent = debugViewContent + Constant.DEBUG_AIR_DIR_DEFROST;
				}	
				else 
					debugViewContent = debugViewContent + Constant.DEBUG_AIR_DIR_DEFROST_ERROR;
				
				if(recircStatus>0.9){
					debugViewContent = debugViewContent + Constant.DEBUG_AIR_DIR_RECIRC;
				}
				else 
					debugViewContent = debugViewContent + Constant.DEBUG_AIR_DIR_RECIRC_ERROR;
				
				if(fanspeedVolt>0.9)
					debugViewContent += Constant.DEBUG_FAN_INFO;
				else 
					debugViewContent += Constant.DEBUG_FAN_INFO_ERROR;
				
				if(compclStatus>0.9){
					debugViewContent += Constant.DEBUG_CC;
				}
				else 
					debugViewContent += Constant.DEBUG_CC_ERROR;
				
				if(monoValveVolt > 0.9){
					debugViewContent += Constant.DEBUG_MV;
				}
				else 
					debugViewContent += Constant.DEBUG_MV_ERROR;
				
				if(Constant.currentACConfig.currTemp.getCurrentTemp()<130 && Constant.currentACConfig.currTemp.getCurrentTemp() > 59)
					debugViewContent += Constant.DEBUG_TEMP;				
				else 
					debugViewContent += Constant.DEBUG_TEMP_ERROR;
				
				debugView.setText(debugViewContent);	
			}
		});
        ACButton.setOnClickListener(new OnClickListener() {			
			public void onClick(View v) {
				if(ACButton.isChecked())
				{
					setEnabledDisableACControls(true); 
					setEnabledControls();
				}
				else 
				{					
					setEnabledDisableACControls(false);
					setActiveMode(0); 
					resumeACControls(true); 
				}				
			}
		});
        SystemButton.setOnClickListener(new OnClickListener() {			
			public void onClick(View v) {
				adminComponent = new ComponentName(ACCActivity.this, AccAdmin.class);
				devicePolicyManager = (DevicePolicyManager) getSystemService(Context.DEVICE_POLICY_SERVICE);

	            if (!devicePolicyManager.isAdminActive(adminComponent)) {

	                Intent intent = new Intent(DevicePolicyManager.ACTION_ADD_DEVICE_ADMIN);
	                intent.putExtra(DevicePolicyManager.EXTRA_DEVICE_ADMIN, adminComponent);
	                startActivityForResult(intent, REQUEST_ENABLE);
	            } else {
	                devicePolicyManager.lockNow();
	                SystemButton.setChecked(true); 
	            }
			} 
		});
    }
    
    public void flipView(int visibility, int debugVisibility)
    {
    	seekFanSpeed.setVisibility(visibility);
		FDbutton1.setVisibility(visibility);
        FDbutton2.setVisibility(visibility);
        FDbutton3.setVisibility(visibility);
        FDbutton4.setVisibility(visibility);
        FDbutton5.setVisibility(visibility);
        FDbutton6.setVisibility(visibility);
        numPick.setVisibility(visibility);
        fan.setVisibility(visibility);
        plus.setVisibility(visibility);
        minus.setVisibility(visibility);       
        debugView.setVisibility(debugVisibility); 
    }
  
    /*
     * Set checked state of the buttons
     */
    public void setActive(int i){
    	switch(i){
    		case 1:    			
    			FDbutton1.setBackgroundColor(Color.GREEN);
    			FDbutton2.setBackgroundDrawable(originDraw);
    			FDbutton3.setBackgroundDrawable(originDraw);
    			FDbutton4.setBackgroundDrawable(originDraw);
    			FDbutton5.setBackgroundDrawable(originDraw);
				break;
    		case 2:
    			FDbutton1.setBackgroundDrawable(originDraw);
    			FDbutton2.setBackgroundColor(Color.GREEN);
    			FDbutton3.setBackgroundDrawable(originDraw);
    			FDbutton4.setBackgroundDrawable(originDraw);
    			FDbutton5.setBackgroundDrawable(originDraw);
				break;
    		case 3:
    			FDbutton1.setBackgroundDrawable(originDraw);
    			FDbutton3.setBackgroundColor(Color.GREEN);
    			FDbutton2.setBackgroundDrawable(originDraw);
    			FDbutton4.setBackgroundDrawable(originDraw);
    			FDbutton5.setBackgroundDrawable(originDraw);
				break;
    		case 4:
    			FDbutton1.setBackgroundDrawable(originDraw);
    			FDbutton4.setBackgroundColor(Color.GREEN);
    			FDbutton2.setBackgroundDrawable(originDraw);
    			FDbutton3.setBackgroundDrawable(originDraw);
    			FDbutton5.setBackgroundDrawable(originDraw);
				break;
    		case 5:
    			FDbutton1.setBackgroundDrawable(originDraw);
    			FDbutton5.setBackgroundColor(Color.GREEN);
    			FDbutton2.setBackgroundDrawable(originDraw);
    			FDbutton3.setBackgroundDrawable(originDraw);
    			FDbutton4.setBackgroundDrawable(originDraw);
				break;
			default:
				FDbutton1.setBackgroundDrawable(originDraw);
    			FDbutton2.setBackgroundColor(Color.GREEN);
    			FDbutton3.setBackgroundDrawable(originDraw);
    			FDbutton4.setBackgroundDrawable(originDraw);
    			FDbutton5.setBackgroundDrawable(originDraw);
				break;
    	}
    }
    /**
     * Set checked state of the modes
     * @param i
     */
    public void setActiveMode(int i){
    	switch(i){
    		case 8:
    			AutoButton.setBackgroundColor(Color.GREEN);
    			ManualButton.setBackgroundDrawable(originDraw);
    			DebugButton.setBackgroundDrawable(originDraw);
    			break; 
    		case 9: 
    			AutoButton.setBackgroundDrawable(originDraw);
    			ManualButton.setBackgroundColor(Color.GREEN);
    			DebugButton.setBackgroundDrawable(originDraw);
    			break; 
    		case 10: 
    			AutoButton.setBackgroundDrawable(originDraw);
    			ManualButton.setBackgroundDrawable(originDraw);
    			DebugButton.setBackgroundColor(Color.GREEN);    			
    			break;    	
    		default:
    			AutoButton.setBackgroundDrawable(originDraw);
    			ManualButton.setBackgroundDrawable(originDraw);
    			DebugButton.setBackgroundDrawable(originDraw);
				break;
    	}
    }   
    
    private void initialAirDirectionButton(FANDIRECTION fanDirection){
    	switch(fanDirection){
		case HeadOnly:
			setActive(Constant.VALUE1);
			break;
		case HeadNFoot:			
			setActive(Constant.VALUE2);
			break;
		case FootOnly:
			setActive(Constant.VALUE3);
			break;
		case DefrostNFoot:
			setActive(Constant.VALUE4);
			break;
		case Defrostonly:
			setActive(Constant.VALUE5);
			break;		
		default:
			setActive(Constant.VALUE2);
		}
    }
    
    /*
     * Get Android's user name
     */
    public String getUsername(){

    	AccountManager manager = AccountManager.get(this); 
    	Account[] accounts = manager.getAccountsByType("com.google"); 
        List<String> possibleEmails = new LinkedList<String>();
        
        for (Account account : accounts) {
          // account.name as an email address only for certain account.type values.
          possibleEmails.add(account.name);
        }
        if(!possibleEmails.isEmpty() && possibleEmails.get(0) != null){
            String email = possibleEmails.get(0);
            String[] parts = email.split("@");
            if(parts.length > 0 && parts[0] != null)
                return parts[0];
            else
                return null;
        }else
            return null;         
	}
    
    public static Context getAppContext() {
        return context;
    }
    
    /**
	 * This is the thread on which all the IOIO activity happens. It will be run
	 * every time the application is resumed and aborted when it is paused. The
	 * method setup() will be called right after a connection with the IOIO has
	 * been established (which might happen several times!). Then, loop() will
	 * be called repetitively until the IOIO gets disconnected.
	 */
	class IOIOThread extends AbstractIOIOActivity.IOIOThread {
		/** The on-board LED. */
		private DigitalOutput headPin;
		private DigitalOutput footPin;
		private DigitalOutput defrostPin;
		private DigitalOutput reciculationPin;
		private DigitalOutput compressorClutchPin;
		private PwmOutput monoValvePin;
		private PwmOutput fanspeed;
		private AnalogInput inputTemp;
		private DigitalOutput outputVolt;
		
		private AnalogInput headInput;		
		private AnalogInput footInput;
		private AnalogInput defrostInput;
		private AnalogInput recirculationInput;
		private AnalogInput compressorClutchInput;
		private AnalogInput monoValveInput;
		private AnalogInput fanspeedInput;		
		
		private AnalogInput monoValveVoltageInput;
		

		/**
		 * Called every time a connection with IOIO has been established.
		 * Typically used to open pins.
		 * 
		 * @throws ConnectionLostException
		 *             When IOIO connection is lost.
		 * 
		 * @see ioio.lib.util.AbstractIOIOActivity.IOIOThread#setup()
		 */
		@Override
		protected void setup() throws ConnectionLostException {	
			try {
				// Initializing mode by basing on the user stored in profile 
				initialMode();		
				
				// Initializing values for each pins of IOIO
				setUpPins();
				
				enableUi(true);
				sleep(10);
			} catch (ConnectionLostException e) {
				enableUi(false);
				throw e;
			} catch (InterruptedException e) {
			}
		}

		/**
		 * Called repetitively while the IOIO is connected.
		 * 
		 * @throws ConnectionLostException
		 *             When IOIO connection is lost.
		 * 
		 * @see ioio.lib.util.AbstractIOIOActivity.IOIOThread#loop()
		 */
		@Override
		protected void loop() throws ConnectionLostException {					
			try {
				headPin.write(Constant.head); // switchovervalve 1
				footPin.write(Constant.foot); // switchovervalve 2
				defrostPin.write(Constant.defrost); // switchovervalve 3
				reciculationPin.write(Constant.reciculation);// switchovervalve 4
				compressorClutchPin.write(Constant.currentACConfig.currComClutch.getStatus());
				fanspeed.setPulseWidth(seekFanSpeed.getProgress());
				outputVolt.write(true);// output 3.3V
				final float volt = inputTemp.getVoltage();
				readTemperatureSensor(volt);		
				//sleep(10);
				autoCheck();
				//sleep(10);
				monoValvePin.setPulseWidth(Constant.currentACConfig.currMonoValve.getMonovalveValue()); 
				
				// reading input
				headStatus = headInput.getVoltage();
				footStatus = footInput.getVoltage();
				defrostStatus = defrostInput.getVoltage();
				recircStatus = recirculationInput.getVoltage();
				compclStatus = compressorClutchInput.getVoltage();
				
				monoValveVolt = monoValveInput.getVoltage();
				fanspeedVolt = fanspeedInput.getVoltage();
				
				
				
			} catch (InterruptedException e) {
			}
		}
		
		private void setUpPins() throws ConnectionLostException
		{
			headPin = ioio_.openDigitalOutput(Constant.VALUE1, false);
			footPin = ioio_.openDigitalOutput(Constant.VALUE2, false);
			defrostPin = ioio_.openDigitalOutput(Constant.VALUE3, false);
			reciculationPin = ioio_.openDigitalOutput(Constant.VALUE4, true);	
			compressorClutchPin = ioio_.openDigitalOutput(Constant.VALUE5, true);
			outputVolt = ioio_.openDigitalOutput(Constant.VALUE6, true);
			inputTemp = ioio_.openAnalogInput(Constant.VALUE40);
			monoValvePin = ioio_.openPwmOutput(Constant.VALUE11,  Constant.FREQUENCY);
			fanspeed = ioio_.openPwmOutput(Constant.VALUE12, Constant.FREQUENCY);
			
			// reading input
			headInput = ioio_.openAnalogInput(Constant.VALUE31);
			footInput = ioio_.openAnalogInput(Constant.VALUE32);
			defrostInput = ioio_.openAnalogInput(Constant.VALUE33);
			recirculationInput = ioio_.openAnalogInput(Constant.VALUE35);
			compressorClutchInput = ioio_.openAnalogInput(Constant.VALUE36);
			monoValveInput = ioio_.openAnalogInput(Constant.VALUE37);
			fanspeedInput = ioio_.openAnalogInput(Constant.VALUE38);	
		}
	}

	/**
	 * A method to create our IOIO thread.
	 * 
	 * @see ioio.lib.util.AbstractIOIOActivity#createIOIOThread()
	 */
	@Override
	protected AbstractIOIOActivity.IOIOThread createIOIOThread() {
		return new IOIOThread();
	}
	
	private void enableUi(final boolean enable) {
		runOnUiThread(new Runnable() {
			@Override
			public void run() {
				seekFanSpeed.setEnabled(enable);
			}
		});
	}
	
	private void readTemperatureSensor(final float volt) {
		runOnUiThread(new Runnable() {
			@Override
			public void run() {
				Constant.currentACConfig.currTemp.setCurrentTemp((int)readTemperatureSensor1(volt));				
			}
		});
	}
	
	private long readTemperatureSensor1(final float volt){					
			float resistance = (float) ((250000)*(volt) / (3.3));
			long tem = Math.round(-21.77*Math.log(resistance)+ 244.8845);
			long fahrenheit = (long)(9.0/5.0*tem + 32);			
			mTextTemp.setText(Long.toString(fahrenheit));			
			Constant.currentACConfig.currTemp.setCurrentTemp((int)fahrenheit);
			Constant.currentTem = fahrenheit;
			return fahrenheit;
	}

	
	/*
	 * Called when the connection established
	 * between IOIO and Android
	 */
	private void initialMode() {
		runOnUiThread(new Runnable() {
			@Override
			public void run() {
				Process.initialMode(getUsername());
				setConfig();		
				numPick.mCurrent = Constant.currentACConfig.currTemp.getCurrentTemp();
				numPick.updateView();	
			}
		});
	}
	
	private void setEnabledControls(){
		switch (Constant.currentACConfig.Mode){
		case Auto:
			setEnabledDisabled(false);
			this.setActiveMode(Constant.VALUE8);
			FDbutton6.setEnabled(true);
			seekFanSpeed.setEnabled(false);
			numPick.setEnabled(true);
			break;
		case Manual:
			setEnabledDisabled(true);
			this.setActiveMode(Constant.VALUE9);
			FDbutton6.setEnabled(true);
			numPick.setEnabled(true);
			seekFanSpeed.setEnabled(true);
			break;
		case Debug:
			setEnabledDisabled(false);
			FDbutton6.setEnabled(false);
			seekFanSpeed.setEnabled(false);
			numPick.setEnabled(false); 
			this.setActiveMode(Constant.VALUE10); 
			break;
		default:			
		}
	}
	
	private void setEnabledDisabled(boolean flag){
		FDbutton1.setEnabled(flag);
		FDbutton2.setEnabled(flag);
		FDbutton3.setEnabled(flag);
		FDbutton4.setEnabled(flag);
		FDbutton5.setEnabled(flag);
		seekFanSpeed.setEnabled(flag);
	}
	private void setEnabledDisableACControls(boolean flag){
		FDbutton1.setEnabled(flag);
		FDbutton2.setEnabled(flag);
		FDbutton3.setEnabled(flag);
		FDbutton4.setEnabled(flag);
		FDbutton5.setEnabled(flag);
		FDbutton6.setEnabled(flag);
		AutoButton.setEnabled(flag);
		ManualButton.setEnabled(flag);
		DebugButton.setEnabled(flag);
		seekFanSpeed.setEnabled(flag);
		numPick.setEnabled(flag);
		
	}
	private void resumeACControls(boolean flag)
	{
		FDbutton1.setEnabled(flag);
		FDbutton2.setEnabled(flag);
		FDbutton3.setEnabled(flag);
		FDbutton4.setEnabled(flag);
		FDbutton5.setEnabled(flag);
		FDbutton6.setEnabled(flag);
		seekFanSpeed.setEnabled(flag);
	}
	public void setConfig(){	
		switch(Constant.currentACConfig.Mode){
		case Auto:
			setConfigTemporary();			
			break;
		case Manual:
			setConfigTemporary();		
			break;
		case Debug:
			break;
		default:
			break;
		}
		this.setEnabledControls();		
	}
	
	private void autoCheck() {
		runOnUiThread(new Runnable() {
			@Override
			public void run() {
				if(Constant.autoFlag){
					autoCheckConfig();			
					seekFanSpeed.setProgress(Constant.currentACConfig.currBlowMotor.getSeekBarValue());
				}
				if(Constant.currentACConfig.Mode == MODE.Manual){
					autoCheckConfig();
				}
			}
		});		
	}
	
	public void autoCheckConfig(){
		Process.autoCheckConfig((int)Constant.currentTem);
	}
	
	private void setConfigTemporary()
	{
		// initial the configuration
		Process.processAirFlowDirection(Constant.currentACConfig.airDirection);				
		seekFanSpeed.setProgress(Constant.currentACConfig.currBlowMotor.getSeekBarValue());
		this.initialAirDirectionButton(Constant.currentACConfig.airDirection);
	}
}